#![no_std]

use core::alloc::Layout;

extern crate alloc;
mod addr;
mod array;
mod c_box;

pub use addr::BusAddr;
pub use array::ArrayCoherent;
pub use c_box::BoxCoherent;

/// 用于表示`DMA`操作的相关信息。
#[derive(Debug, Clone, Copy)]
pub struct DMAInfo {
    /// `cpu_addr` 字段表示`CPU`访问该内存区域的地址。
    /// 这个地址是虚拟内存地址，用于`CPU`对内存的访问。
    pub cpu_addr: usize,
    /// `bus_addr` 字段表示该内存区域在总线上的物理地址。
    /// `DMA`控制器使用这个地址来直接访问内存。
    pub bus_addr: u64,
}

/// 实现接口的`trait`，用于设备驱动程序中处理`DMA`分配和释放。
///
/// 此`trait`定义了设备驱动程序在操作系统中为DMA分配和释放内存时所需的操作。
/// 由于这些操作涉及到底层硬件和内存管理的细节，因此它们都被标记为unsafe。
pub unsafe trait Impl {
    /// 分配符合指定布局的一致性内存，操作系统需保证该布局的内存是连续的，且具有读写一致性。
    ///
    /// - `layout`: 描述所需内存布局的结构体。
    ///
    /// 返回一个Option<[DMAInfo]>，表示分配结果。如果分配成功，则包含`DMA`信息；如果失败，则为[None]。
    unsafe fn alloc_coherent(layout: Layout) -> Option<DMAInfo>;
    /// 释放之前为`DMA`分配的一致性内存。
    ///
    /// - `dma`: 待释放的`DMA`内存的信息。
    /// - `layout`: 与待释放`DMA`内存相关的布局信息。
    ///
    /// 此函数负责确保分配的`DMA`内存被正确地释放，并且任何相关的硬件缓存都被刷新。
    unsafe fn dealloc_coherent(dma: DMAInfo, layout: Layout);
}

#[macro_export]
macro_rules! set_impl {
    ($t: ty) => {
        #[no_mangle]
        unsafe fn _os_dma_0_1_alloc_coherent(
            layout: core::alloc::Layout,
        ) -> Option<$crate::DMAInfo> {
            <$t as $crate::Impl>::alloc_coherent(layout)
        }
        #[no_mangle]
        unsafe fn _os_dma_0_1_dealloc_coherent(dma: $crate::DMAInfo, layout: core::alloc::Layout) {
            <$t as $crate::Impl>::dealloc_coherent(dma, layout);
        }
    };
}

#[inline(always)]
pub(crate) unsafe fn alloc_coherent(layout: Layout) -> Option<DMAInfo> {
    extern "Rust" {
        fn _os_dma_0_1_alloc_coherent(layout: Layout) -> Option<DMAInfo>;
    }

    #[allow(clippy::unit_arg)]
    _os_dma_0_1_alloc_coherent(layout)
}

#[inline(always)]
pub(crate) unsafe fn dealloc_coherent(dma: DMAInfo, layout: Layout) {
    extern "Rust" {
        fn _os_dma_0_1_dealloc_coherent(dma: DMAInfo, layout: Layout);
    }

    #[allow(clippy::unit_arg)]
    _os_dma_0_1_dealloc_coherent(dma, layout)
}
